#include "com_nhncorp_pleiades_client_NativeLockEventHandler.h"
#include "pleiades.h"
#include <pthread.h>

extern struct list_head evHandlerList;
extern pthread_mutex_t evHandlerListLock;

extern int getLockEventData(JNIEnv *env, jobject jHandler, 
					 jobject jEventData, pleiades_lock_event_data_t *eventData);

static pleiades_event_handler_t *getPleiadesEventHandler(jobject jobj)
{
	pleiades_event_handler_t *pos;
	void *objaddr = *(void **)jobj;

	if (list_empty(&evHandlerList))
		return NULL;

	list_for_each_entry(pos, &evHandlerList, pleiades_event_handler_t, link) 
		if (objaddr == *(void **)pos->obj)
			break;

	return pos;
}

static void callEventMonitor(pleiades_event_handler_t *handler, 
						pleiades_event_t event, 
						pleiades_lock_event_data_t *eventData) {
	pleiades_lock_event_monitor_t *mon;
	pleiades_constraint_t *constr;
	pleiades_condition_t *cond;
	int should_be_called = 1;
	char *p, *q;

	list_for_each_entry(mon, &handler->event_monitors, 
							pleiades_lock_event_monitor_t, link) {
		if (mon->filter == NULL)
			continue;

		list_for_each_entry(constr, &mon->filter->constr_list, 
									pleiades_constraint_t, link) {
			list_for_each_entry(cond, &constr->cond_list, 
										pleiades_condition_t, link) {
				switch (cond->op) {
					case PLEIADES_EQ:
						if (strcasecmp(eventData->lock_id, cond->key) != 0)
							should_be_called = 0;
						break;
							
					case PLEIADES_LT:
						if (strcasecmp(eventData->lock_id, cond->key) >= 0)
							should_be_called = 0;
						break;

					case PLEIADES_GT:
						if (strcasecmp(eventData->lock_id, cond->key) <= 0)
							should_be_called = 0;
						break;

					case PLEIADES_GE:
						if (strcasecmp(eventData->lock_id, cond->key) < 0)
							should_be_called = 0;
						break;

					case PLEIADES_LE:
						if (strcasecmp(eventData->lock_id, cond->key) > 0)
							should_be_called = 0;
						break;

					case PLEIADES_PF:
						if (strncasecmp(eventData->lock_id, cond->key, 
									strlen(cond->key)) != 0)
							should_be_called = 0;
						break;

					case PLEIADES_SF:
						p = eventData->lock_id+strlen(eventData->lock_id)-1;
						q = cond->key+strlen(cond->key)-1;
						while (p >= eventData->lock_id && q >= cond->key) {
							if (*p != *q)
								break;
							p--;
							q--;
						}

						if (q != cond->key-1)
							should_be_called = 0;
						break;

					case PLEIADES_ANY:
						continue;
						break;

					case PLEIADES_NE:
						if (strcasecmp(eventData->lock_id, cond->key) == 0)
							should_be_called = 0;
						break;

					case PLEIADES_SS:
						if (strstr(eventData->lock_id, cond->key) == NULL)
							should_be_called = 0;
						break;

					default:
						break;
				}
			}
		}

		if (should_be_called)
			mon->notify_event(event, eventData);
	}
}	

/*
 * Class:     com_nhncorp_pleiades_client_NativeLockEventHandler
 * Method:    contentsModified
 * Signature: (Lcom/nhncorp/pleiades/client/pleiades_lock_event_data_t;)V
 */
JNIEXPORT void JNICALL Java_com_nhncorp_pleiades_client_NativeLockEventHandler_contentsModified
  (JNIEnv *env, jobject jobj, jobject jeventData) 
{
	pleiades_event_handler_t *evh;
	pleiades_lock_event_data_t *eventData;

	pthread_mutex_lock(&evHandlerListLock);
	evh = getPleiadesEventHandler(jobj);
	if (evh != NULL && evh->contents_modified != NULL) {
		pthread_mutex_unlock(&evHandlerListLock);
    	eventData = calloc(1, sizeof(pleiades_lock_event_data_t));
		getLockEventData(env, jobj, jeventData, eventData);
		evh->contents_modified(eventData);
		callEventMonitor(evh, PLEIADES_CONTENTS_CHANGED, eventData);
		pleiades_free_lock_event_data(eventData, 1);
	}
	pthread_mutex_unlock(&evHandlerListLock);
}

/*
 * Class:     com_nhncorp_pleiades_client_NativeLockEventHandler
 * Method:    nodeAdded
 * Signature: (Lcom/nhncorp/pleiades/client/pleiades_lock_event_data_t;)V
 */
JNIEXPORT void JNICALL Java_com_nhncorp_pleiades_client_NativeLockEventHandler_nodeAdded
  (JNIEnv *env, jobject jobj, jobject jeventData)
{
	pleiades_event_handler_t *evh;
	pleiades_lock_event_data_t *eventData;

	pthread_mutex_lock(&evHandlerListLock);
	evh = getPleiadesEventHandler(jobj);
	if (evh != NULL && evh->node_added != NULL) {
		pthread_mutex_unlock(&evHandlerListLock);
    	eventData = calloc(1, sizeof(pleiades_lock_event_data_t));
		getLockEventData(env, jobj, jeventData, eventData);
		evh->node_added(eventData);
		callEventMonitor(evh, PLEIADES_NODE_ADDED, eventData);
		pleiades_free_lock_event_data(eventData, 1);
	}
	pthread_mutex_unlock(&evHandlerListLock);
}

/*
 * Class:     com_nhncorp_pleiades_client_NativeLockEventHandler
 * Method:    nodeRemoved
 * Signature: (Lcom/nhncorp/pleiades/client/pleiades_lock_event_data_t;)V
 */
JNIEXPORT void JNICALL Java_com_nhncorp_pleiades_client_NativeLockEventHandler_nodeRemoved
  (JNIEnv *env, jobject jobj, jobject jeventData)
{
	pleiades_event_handler_t *evh;
	pleiades_lock_event_data_t *eventData;

	pthread_mutex_lock(&evHandlerListLock);
	evh = getPleiadesEventHandler(jobj);
	if (evh != NULL && evh->node_removed != NULL) {
		pthread_mutex_unlock(&evHandlerListLock);
    	eventData = calloc(1, sizeof(pleiades_lock_event_data_t));
		getLockEventData(env, jobj, jeventData, eventData);
		evh->node_removed(eventData);
		callEventMonitor(evh, PLEIADES_NODE_REMOVED, eventData);
		pleiades_free_lock_event_data(eventData, 1);
	}
	pthread_mutex_unlock(&evHandlerListLock);
}

/*
 * Class:     com_nhncorp_pleiades_client_NativeLockEventHandler
 * Method:    nodeModified
 * Signature: (Lcom/nhncorp/pleiades/client/pleiades_lock_event_data_t;)V
 */
JNIEXPORT void JNICALL Java_com_nhncorp_pleiades_client_NativeLockEventHandler_nodeModified
  (JNIEnv *env, jobject jobj, jobject jeventData)
{
	pleiades_event_handler_t *evh;
	pleiades_lock_event_data_t *eventData;

	pthread_mutex_lock(&evHandlerListLock);
	evh = getPleiadesEventHandler(jobj);
	if (evh != NULL && evh->node_modified != NULL) {
		pthread_mutex_unlock(&evHandlerListLock);
    	eventData = calloc(1, sizeof(pleiades_lock_event_data_t));
		getLockEventData(env, jobj, jeventData, eventData);
		evh->node_modified(eventData);
		callEventMonitor(evh, PLEIADES_NODE_MODIFIED, eventData);
		pleiades_free_lock_event_data(eventData, 1);
	}
	pthread_mutex_unlock(&evHandlerListLock);
}

/*
 * Class:     com_nhncorp_pleiades_client_NativeLockEventHandler
 * Method:    masterFailover
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_nhncorp_pleiades_client_NativeLockEventHandler_masterFailover
  (JNIEnv *env, jobject jobj)
{
	pleiades_event_handler_t *evh;

	pthread_mutex_lock(&evHandlerListLock);
	evh = getPleiadesEventHandler(jobj);
	if (evh != NULL && evh->master_failover != NULL) {
		pthread_mutex_unlock(&evHandlerListLock);
		evh->master_failover();
		callEventMonitor(evh, PLEIADES_MASTER_FAILOVER, NULL);
	}
	pthread_mutex_unlock(&evHandlerListLock);
}

/*
 * Class:     com_nhncorp_pleiades_client_NativeLockEventHandler
 * Method:    sessionWarning
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_nhncorp_pleiades_client_NativeLockEventHandler_sessionWarning
  (JNIEnv *env, jobject jobj)
{
	pleiades_event_handler_t *evh;

	pthread_mutex_lock(&evHandlerListLock);
	evh = getPleiadesEventHandler(jobj);
	if (evh != NULL && evh->session_warning != NULL) {
		pthread_mutex_unlock(&evHandlerListLock);
		evh->session_warning();
		callEventMonitor(evh, PLEIADES_SESSION_WARNING, NULL);
	}
	pthread_mutex_unlock(&evHandlerListLock);
}

/*
 * Class:     com_nhncorp_pleiades_client_NativeLockEventHandler
 * Method:    sessionSafe
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_nhncorp_pleiades_client_NativeLockEventHandler_sessionSafe
  (JNIEnv *env, jobject jobj)
{
	pleiades_event_handler_t *evh;

	pthread_mutex_lock(&evHandlerListLock);
	evh = getPleiadesEventHandler(jobj);
	if (evh != NULL && evh->session_safe != NULL) {
		pthread_mutex_unlock(&evHandlerListLock);
		evh->session_safe();
		callEventMonitor(evh, PLEIADES_SESSION_SAFE, NULL);
	}
	pthread_mutex_unlock(&evHandlerListLock);
}

/*
 * Class:     com_nhncorp_pleiades_client_NativeLockEventHandler
 * Method:    sessionExpired
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_nhncorp_pleiades_client_NativeLockEventHandler_sessionExpired
  (JNIEnv *env, jobject jobj)
{
	pleiades_event_handler_t *evh;

	pthread_mutex_lock(&evHandlerListLock);
	evh = getPleiadesEventHandler(jobj);
	if (evh != NULL && evh->session_expired != NULL) {
		pthread_mutex_unlock(&evHandlerListLock);
		evh->session_expired();
		callEventMonitor(evh, PLEIADES_SESSION_EXPIRED, NULL);
	}
	pthread_mutex_unlock(&evHandlerListLock);
}

/*
 * Class:     com_nhncorp_pleiades_client_NativeLockEventHandler
 * Method:    clientExpired
 * Signature: (Lcom/nhncorp/pleiades/client/pleiades_lock_event_data_t;)V
 */
JNIEXPORT void JNICALL Java_com_nhncorp_pleiades_client_NativeLockEventHandler_clientExpired
  (JNIEnv *env, jobject jobj, jobject jeventData)
{
	pleiades_event_handler_t *evh;
	pleiades_lock_event_data_t *eventData;

	pthread_mutex_lock(&evHandlerListLock);
	evh = getPleiadesEventHandler(jobj);
	if (evh != NULL && evh->client_expired != NULL) {
		pthread_mutex_unlock(&evHandlerListLock);
    	eventData = calloc(1, sizeof(pleiades_lock_event_data_t));
		getLockEventData(env, jobj, jeventData, eventData);
		evh->client_expired(eventData);
		callEventMonitor(evh, PLEIADES_CLIENT_EXPIRED, eventData);
		pleiades_free_lock_event_data(eventData, 1);
	}
	pthread_mutex_unlock(&evHandlerListLock);
}

/*
 * Class:     com_nhncorp_pleiades_client_NativeLockEventHandler
 * Method:    lockExpired
 * Signature: (Lcom/nhncorp/pleiades/client/pleiades_lock_event_data_t;)V
 */
JNIEXPORT void JNICALL Java_com_nhncorp_pleiades_client_NativeLockEventHandler_lockExpired
  (JNIEnv *env, jobject jobj, jobject jeventData)
{
	pleiades_event_handler_t *evh;
	pleiades_lock_event_data_t *eventData;

	pthread_mutex_lock(&evHandlerListLock);
	evh = getPleiadesEventHandler(jobj);
	if (evh != NULL && evh->lock_expired != NULL) {
		pthread_mutex_unlock(&evHandlerListLock);
    	eventData = calloc(1, sizeof(pleiades_lock_event_data_t));
		getLockEventData(env, jobj, jeventData, eventData);
		evh->lock_expired(eventData);
		callEventMonitor(evh, PLEIADES_LOCK_EXPIRED, eventData);
		pleiades_free_lock_event_data(eventData, 1);
	}
	pthread_mutex_unlock(&evHandlerListLock);
}
